(function(window){  
    var base64 = {};  

        base64.b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

        base64.b64tab = function(bin) {

            var t = {};

            for (var i = 0,

            l = bin.length; i < l; i++) t[bin.charAt(i)] = i;

            return t;

        } (base64.b64chars);

        base64.fromCharCode = String.fromCharCode;

        // encoder stuff

        base64.cb_utob = function(c) {

            if (c.length < 2) {

                var cc = c.charCodeAt(0);

                return cc < 0x80 ? c: cc < 0x800 ? (base64.fromCharCode(0xc0 | (cc >>> 6)) + base64.fromCharCode(0x80 | (cc & 0x3f))) : (base64.fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) + base64.fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + base64.fromCharCode(0x80 | (cc & 0x3f)));

            } else {

                var cc = 0x10000 + (c.charCodeAt(0) - 0xD800) * 0x400 + (c.charCodeAt(1) - 0xDC00);

                return (base64.fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) + base64.fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) + base64.fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + base64.fromCharCode(0x80 | (cc & 0x3f)));

            }

        };

        base64.re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;

        base64.utob = function(u) {

            return u.replace(base64.re_utob, base64.cb_utob);

        };

        base64.cb_encode = function(ccc) {

            var padlen = [0, 2, 1][ccc.length % 3],

            ord = ccc.charCodeAt(0) << 16 | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)),

            chars = [base64.b64chars.charAt(ord >>> 18), base64.b64chars.charAt((ord >>> 12) & 63), padlen >= 2 ? '=': base64.b64chars.charAt((ord >>> 6) & 63), padlen >= 1 ? '=': base64.b64chars.charAt(ord & 63)];

            return chars.join('');

        };

        base64.btoa = function(b) {

            return b.replace(/[\s\S]{1,3}/g, base64.cb_encode);

        };

        base64._encode = function(u) {

            return base64.btoa(base64.utob(u))

        };

        base64.encode = function(u, urisafe) {

            return ! urisafe ? base64._encode(String(u)) : base64._encode(String(u)).replace(/[+\/]/g,

            function(m0) {

                return m0 == '+' ? '-': '_';

            }).replace(/=/g, '');

        };

        base64.encodeURI = function(u) {

            return base64.encode(u, true)

        };

        // decoder stuff

        base64.re_btou = new RegExp(['[\xC0-\xDF][\x80-\xBF]', '[\xE0-\xEF][\x80-\xBF]{2}', '[\xF0-\xF7][\x80-\xBF]{3}'].join('|'), 'g');

        base64.cb_btou = function(cccc) {

            switch (cccc.length) {

            case 4:

                var cp = ((0x07 & cccc.charCodeAt(0)) << 18) | ((0x3f & cccc.charCodeAt(1)) << 12) | ((0x3f & cccc.charCodeAt(2)) << 6) | (0x3f & cccc.charCodeAt(3)),

                offset = cp - 0x10000;

                return (base64.fromCharCode((offset >>> 10) + 0xD800) + base64.fromCharCode((offset & 0x3FF) + 0xDC00));

            case 3:

                return base64.fromCharCode(((0x0f & cccc.charCodeAt(0)) << 12) | ((0x3f & cccc.charCodeAt(1)) << 6) | (0x3f & cccc.charCodeAt(2)));

            default:

                return base64.fromCharCode(((0x1f & cccc.charCodeAt(0)) << 6) | (0x3f & cccc.charCodeAt(1)));

            }

        };

        base64.btou = function(b) {

            return b.replace(base64.re_btou, base64.cb_btou);

        };

        base64.cb_decode = function(cccc) {

            var len = cccc.length,

            padlen = len % 4,

            n = (len > 0 ? base64.b64tab[cccc.charAt(0)] << 18 : 0) | (len > 1 ? base64.b64tab[cccc.charAt(1)] << 12 : 0) | (len > 2 ? base64.b64tab[cccc.charAt(2)] << 6 : 0) | (len > 3 ? base64.b64tab[cccc.charAt(3)] : 0),

            chars = [base64.fromCharCode(n >>> 16), base64.fromCharCode((n >>> 8) & 0xff), base64.fromCharCode(n & 0xff)];

            chars.length -= [0, 0, 2, 1][padlen];

            return chars.join('');

        };

        base64.atob = function(a) {

            return a.replace(/[\s\S]{1,4}/g, base64.cb_decode);

        };

        base64._decode =function(a) {

            return base64.btou(base64.atob(a))

        };

        base64.decode = function(a) {

            return base64._decode(String(a).replace(/[-_]/g,

            function(m0) {

                return m0 == '-' ? '+': '/'

            }).replace(/[^A-Za-z0-9\+\/]/g, ''));

        };
      
    window.base64 = base64;  
 })(window);  